package com.android.BluethootChess.ui;

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Point;

import com.android.BluethootChess.activity.R;
import com.android.BluethootChess.model.GameBoardMatrix;
import com.android.BluethootChess.model.PieceTypeAndColor;
import com.android.BluethootChess.model.Square;
import com.android.BluethootChess.model.SquarePosition;
import com.android.BluethootChess.util.Utils;

/**
 * Deseneaza elementele pe tabla.
 * */
public class Drawing {
	private Bitmap bitmapImage;
	private Bitmap[] pieces;
	private Context context;
	private int[] boardColors;
	private UISquares squares;

	public Drawing(Bitmap image, Context context) {
		bitmapImage = image;
		pieces = new Bitmap[6 * 2];
		this.context = context;
		loadPieces();
	}
	
	public void setBoardColors(int[] boardColors) {
		this.boardColors = boardColors;
	}

	public void setSquares(UISquares squares) {
		this.squares = squares;
	}

	/**
	 * Deseneaza piesele in image-ul setat in constructor folosind o matrice in
	 * care sunt stocate piesele pe tabla.
	 * 
	 * @param gameMatrix
	 *            - reprezentarea din model
	 * @param squares
	 *            - reprezinta patratele tablei
	 * @param map
	 *            - mapeaza cod piesa - imagine piesa
	 * */
	public void drawPieces(GameBoardMatrix gameMatrix, Square[][] squares) {

		Map<Integer, Bitmap> map = new HashMap<Integer, Bitmap>();

		for (PieceTypeAndColor p : PieceTypeAndColor.values()) {
			map.put(p.ordinal(), pieces[p.ordinal()]);
		}

		byte[][] matrix = gameMatrix.getGameBoard();

		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				if (matrix[i][j] != -1) {
					int code = (int) matrix[i][j];
					Bitmap piece = map.get(code);
					if (piece != null) {
						Square square = squares[i][j];
						int x = square.getLowerPoint().x;
						int y = square.getLowerPoint().y;
						drawBitmapShape(x, y, piece, Color.WHITE, -1);
					}
				}
			}
		}
	}

	/***
	 * Deseneaza o imagine intr-o alta imagine, eliminand o culoare de fundal
	 * Functia verifica daca se poate desena aceasta imagine.
	 * 
	 * @param x
	 * @param y
	 *            - coordonatele unde se va desena imaginea
	 * @param cpyImage
	 *            - imaginea care se va copia la coordonatele x,y
	 * @param ignoreColor
	 *            - va ignora aceasta culoare din imagine
	 *@param fillColor
	 *            - daca e diferit -1 , va colora forma din imagine ce se va
	 *            copia.
	 * */
	public void drawBitmapShape(int x, int y, Bitmap cpyImage, int ignoreColor,	int fillColor) {

		boolean cond1 = x + cpyImage.getWidth() < bitmapImage.getWidth();
		boolean cond2 = y + cpyImage.getHeight() < bitmapImage.getHeight();

		if (cond1 && cond2) {
			int ii = 0;
			int jj = 0;
			for (int i = x; i < x + cpyImage.getWidth(); i++) {
				for (int j = y; j < y + cpyImage.getHeight(); j++) {
					if (cpyImage.getPixel(ii, jj) != ignoreColor) {
						if (fillColor == -1) {
							bitmapImage.setPixel(i, j, cpyImage.getPixel(ii, jj));
						} else {
							bitmapImage.setPixel(i, j, fillColor);
						}
					}
					jj++;
				}
				jj = 0;
				ii++;
			}
		}
	}

	/**
	 * Creaza un array cu piesele ce trebuiesc desenate pe tabla.
	 * */
	// TODO incerca sa cureti codul asta, nu e prea frumos.
	private void loadPieces() {
		pieces[PieceTypeAndColor.BLACK_BISHOP.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.bishop);
		pieces[PieceTypeAndColor.BLACK_KING.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.king);
		pieces[PieceTypeAndColor.BLACK_KNIGHT.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.knight);
		pieces[PieceTypeAndColor.BLACK_PAWN.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.pawn);
		pieces[PieceTypeAndColor.BLACK_QUEEN.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.queen);
		pieces[PieceTypeAndColor.BLACK_ROOK.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.rook);

		pieces[PieceTypeAndColor.WHITE_BISHOP.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.bishopw);
		pieces[PieceTypeAndColor.WHITE_KING.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.kingw);
		pieces[PieceTypeAndColor.WHITE_KNIGHT.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.knightw);
		pieces[PieceTypeAndColor.WHITE_PAWN.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.pawnw);
		pieces[PieceTypeAndColor.WHITE_QUEEN.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.queenw);
		pieces[PieceTypeAndColor.WHITE_ROOK.ordinal()] = BitmapFactory
				.decodeResource(context.getResources(), R.drawable.rookw);
	}

	/**
	 * Muta o piesa la o alta locatie.
	 * 
	 * @param from
	 *            - locatia initiala.
	 * @param dest
	 *            - pozitia finala.
	 * @param fromColor
	 *            - culoarea de fundal pentru piesa ce se muta
	 * */
	public void movePiece(Point from, Point dest, int fromColor, int toColor) {
		int pictureX = Utils.BOARD_WIDTH / Utils.BOARD_SIZE;
		int pictureY = Utils.BOARD_HEIGHT / Utils.BOARD_SIZE;

		redrawSquare(dest, pictureX, pictureY, toColor);

		int jj = dest.y;
		int ii = dest.x;

		for (int i = from.x; i < from.x + pictureX; i++) {
			for (int j = from.y; j < from.y + pictureY; j++) {

				int pixelColor = bitmapImage.getPixel(i, j);
				if (pixelColor != fromColor) {
					bitmapImage.setPixel(ii, jj, pixelColor);
				}
				jj++;
			}
			jj = dest.y;
			ii++;
		}

		redrawSquare(from, pictureX, pictureY, fromColor);
	}

	/**Deseneaza un patrat cu culoarea color.
	 * @param point - punctul de inceput a patratului
	 * @param offsetX - cat din patrat se doreste colorat
	 * @param offsetY - cat din inaltime se coloreaza
	 * @param color - Culoarea cu care se deseneaza patratul.
	 * */
	private void redrawSquare(Point point, int offsetX, int offsetY, int color) {
		for (int i = point.x; i < point.x + offsetX; i++) {
			for (int j = point.y; j < point.y + offsetY; j++) {
				bitmapImage.setPixel(i, j, color);
			}
		}
	}
	/**
	 * Evidentiaza patratul selectat.
	 * */
	public void highlightSelectedSquare(SquarePosition selectedSquare,
			int highlightColor, int actualColor) {
		int x = selectedSquare.x;
		int y = selectedSquare.y;
		Square square = squares.getSquares()[x][y];

		for (int i = square.getLowerPoint().x; i < square.getHigherPoint().x; i++) {
			for (int j = square.getLowerPoint().y; j < square.getHigherPoint().y; j++) {
				if (bitmapImage.getPixel(i, j) == actualColor) {
					bitmapImage.setPixel(i, j, highlightColor);
				}
			}
		}
	}
	
	/**
	 * Sterge culorea de fundal, dupa un highlight
	 * */
	public void cleanSelectedSquare(SquarePosition selectedSquare,
			int highlightColor) {
		highlightSelectedSquare(selectedSquare, getSquareColorAt(
				selectedSquare.x, selectedSquare.y), highlightColor);
	}
	
	
	/**
	 * Returneaza culoarea patratului de la coord x,y
	 * */
	public int getSquareColorAt(int x, int y) {
		if ((x % 2 == 0 && y % 2 == 0) || (x % 2 == 1 && y % 2 == 1)) {
			return boardColors[0];
		} else {
			return boardColors[1];
		}
	}

}
